<template>
  <div>
    <div class="ml-12px">
      <el-button @click="openFile">上传文件</el-button>
      <input
        type="file"
        id="upload_file"
        class="hidden"
        multiple
        @change="upload"
        :accept="[...videoAccept, ...imageAccept].join(',')"
        ref="uploadRef"
      />
      <el-button class="ml-12px" @click="listVisible = true" type="primary">上传列表</el-button>
    </div>
    <el-dialog v-model="listVisible" title="文件列表">
      <div>
        <el-tag>文件上传过程中请勿跳转页面或者刷新页面，否则文件上传失败</el-tag>
      </div>
      <div class="pt-20px">
        <div v-for="(p, index) in fileList" :key="index">
          <div>{{ p.file.name }}</div>
          <el-progress :percentage="Math.floor((p.index / p.chunkTotal) * 100)"></el-progress>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { uploadFile } from "@/api/modules/file";
import { generateUUID } from "@/utils";
import { ElMessage } from "element-plus";
import md5 from "js-md5";
// import SparkMD5 from "spark-md5";
import { ref } from "vue";

// -----------传输完成
const emits = defineEmits(["success"]);

// ---------下载列表

interface FileList<T> {
  chunkTotal: number;
  index: number;
  file: T;
}

const listVisible = ref(false);
const fileList = ref<FileList<File>[]>();

// ----------下载操作
type Props = {
  pid: number;
  refresh?: (params: any) => Promise<any>;
};

const props = withDefaults(defineProps<Props>(), {
  pid: 0
});

const videoAccept = ["video/mp4"];
const imageAccept = ["image/jpg", "image/png", "image/jpeg", "image/gif"];
// const limit = 1024 * 1024 * 1024;

const openFile = () => {
  let uploadRef = document.getElementById("upload_file");
  uploadRef!.click();
};

const upload = async ({ target: { files } }: HTMLElement | any) => {
  let arr = [];
  let smallMulti = []; //小文件的多文件上传
  // 如果文件列表长度不为0就显示文件列表
  if (files.length !== 0) {
    let data: FileList<File>[] = [];
    for (let i = 0; i < files.length; i++) {
      data.push({ chunkTotal: 1, index: 0, file: files[i] });
    }
    fileList.value = data;
    listVisible.value = true;
  }

  for (let i = 0; i < files.length; i++) {
    if (files[i].size >= 2 * 100 * 1024) {
      arr.push(files[i]);
    } else {
      smallMulti.push(files[i]);
    }
  }
  Promise.all([concurrency(arr), smallMultiUpload(smallMulti)]);
};

// 并发
const concurrency = async (files: File[]) => {
  if (files.length === 0) return;
  for (let j = 0; j < files.length; j++) {
    if (!files[j]) return;
    const { size, name, type } = files[j];
    const chunkSize = 2 * 100 * 1024; //每个切片的大小
    const chunks = handleFile(files[j], chunkSize);
    const fileMD5 = md5(generateUUID());
    const ext = name.match(/\.\w+$/)![0];
    const fileName = ext ? md5(generateUUID() + name) + ext : md5(generateUUID() + name);
    for (let i = 0; i < chunks.length; i++) {
      let Form = new FormData();
      Form.append("fileMD5", fileMD5 as string);
      Form.append("file", chunks[i]);
      Form.append("index", i.toString());
      Form.append("fileName", name);
      Form.append("ossFilename", fileName);
      Form.append("chunkTotal", chunks.length.toString());
      Form.append("totalSize", size.toString());
      Form.append("type", type);
      const { data } = await uploadFile(Form, props.pid);
      // 找出对应的名字的文件
      const index = fileList.value?.findIndex((e: FileList<File>) => e.file.name === (data as any).fileName);
      if (index !== -1) {
        console.log(fileName, index);
        fileList.value![index as number].chunkTotal = (data as any).chunkTotal;
        fileList.value![index as number].index = (data as any).index;
      }
      console.log(data);
      console.log(fileList.value);
    }
    if (isFinishTrans()) {
      ElMessage.success("传输完成");
      emits("success");
    }
  }
};

// 小文件的多文件上传
const smallMultiUpload = async (files: File[]) => {
  if (files.length === 0) return;

  for (let i = 0; i < files.length; i++) {
    let Form = new FormData();
    const filename = md5(generateUUID()) + files[i].name.match(/\.\w+$/)![0];
    Form.append("file", files[i]);
    Form.append("fileName", filename);
    const { data } = await uploadFile(Form, props.pid);
    console.log(data);
    // 找出对应的名字的文件
    const index = fileList.value?.findIndex((e: FileList<File>) => e.file.name === (data as any).fileName);
    if (index !== -1) {
      console.log(filename, index);
      fileList.value![index as number].chunkTotal = (data as any).chunkTotal;
      fileList.value![index as number].index = (data as any).index;
    }
  }
  if (isFinishTrans()) {
    ElMessage.success("传输完成");
    emits("success");
  }
};

// 判断是否已经完成传输
const isFinishTrans = () => {
  for (let i = 0; i < fileList.value!.length; i++) {
    if (fileList.value![i].chunkTotal !== fileList.value![i].index) {
      return false;
    }
  }
  return true;
};

// 为文件分片
const handleFile = (file: File, chunkSize: number) => {
  let chunks = [];
  const totalChunks = Math.ceil(file.size / chunkSize);
  for (let i = 0; i < totalChunks; i++) {
    let start = i * chunkSize;
    let end = Math.min(file.size, start + chunkSize);
    let blob = file.slice(start, end);
    chunks.push(blob);
  }
  return chunks;
};

// 增量算法 分片hash
// const hash = (chunks: Blob[]) => {
//   return new Promise(resolve => {
//     const spark = new SparkMD5();
//     function _read(i: number) {
//       if (i >= chunks.length) {
//         resolve(spark.end());
//         return;
//       }
//       const blob = chunks[i];
//       const reader = new FileReader();
//       reader.onload = (e: any) => {
//         const bytes = e.target.result; //读取的字节
//         spark.append(bytes);
//         _read(i + 1);
//       };
//       reader.readAsArrayBuffer(blob);
//     }
//     _read(0);
//   });
// };
</script>

<style></style>
